package com.ruicar.afs.cloud.bizcommon.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruicar.afs.cloud.bizcommon.dto.print.PrintDto;
import com.ruicar.afs.cloud.bizcommon.enums.TemplatePrintType;
import com.ruicar.afs.cloud.bizcommon.proxy.ExtITextFontRegistry;
import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions;
import fr.opensagres.xdocreport.converter.ConverterTypeTo;
import fr.opensagres.xdocreport.converter.ConverterTypeVia;
import fr.opensagres.xdocreport.converter.Options;
import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.images.ByteArrayImageProvider;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

/**
 * 打印工具类
 *
 * @author pangh
 */
@UtilityClass
@Slf4j
public class TemplatePrintUtil {

    /**
     * @param dto
     * @return
     */
    public Boolean print(PrintDto dto) {
        // 数据检查
        checkPrintDto(dto);
        InputStream in = dto.getIn();
        OutputStream out = dto.getOut();
        try {
            in = in == null ? FileUtil.getInputStream(dto.getInPath()) : in;
            out = out == null ? FileUtil.getOutputStream(dto.getOutPath()) : out;
            // 初始化模板合成
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Velocity);
            FieldsMetadata fieldsMetadata = report.createFieldsMetadata();
            IContext context = report.createContext();
            // 数据填充
            JSONObject.parseObject(dto.getJson()).forEach((k, v) -> {
                // list数据需要填充字段
                if (v.getClass().equals(JSONArray.class)) {
                    setFieldsMetadata(Convert.toList(Map.class, v), k, fieldsMetadata);
                }
                // modify by sijun.yu 2020-10-13 为支持添加图片做处理
                if ("rqCode".equals(k)){
                    fieldsMetadata.addFieldAsImage(k.toString());
                    try{
                        byte[] bytes = new BASE64Decoder().decodeBuffer(v.toString());
                        context.put(k, new ByteArrayImageProvider(bytes));
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }else{
                    context.put(k, v);
                }
            });
            // 生成模板
            if (StrUtil.endWithIgnoreCase(dto.getOutPath(), StrUtil.DOT + TemplatePrintType.PDF.name())) {
                // modify by sijun.yu 2020-08-13 判断操作系统
                if(System.getProperty("os.name").toLowerCase().startsWith("window")){
                    Options options = Options.getTo(ConverterTypeTo.PDF).via(ConverterTypeVia.XWPF);
                    report.convert(context, options, out);
                }else{
                    ExtITextFontRegistry fontProvider = ExtITextFontRegistry.getRegistry();
                    PdfOptions pdfOptions = PdfOptions.create();
                    pdfOptions.fontProvider(fontProvider);
                    Options options = Options.getTo(ConverterTypeTo.PDF).via(ConverterTypeVia.XWPF);
                    options.subOptions(pdfOptions);
                    report.convert(context, options, out);
                }
            } else {
                report.process(context, out);
            }

        } catch (IOException e) {
            log.error("模板读取失败", e);
            return Boolean.FALSE;
        } catch (XDocReportException e) {
            log.error("模板合成失败", e);
            return Boolean.FALSE;
        } finally {
            // 释放资源
            XDocReportRegistry.getRegistry().dispose();
            IoUtil.close(in);
            IoUtil.close(out);
        }

        return Boolean.TRUE;
    }

    /**
     * list设置填充字段
     *
     * @param list
     * @param key
     * @param fieldsMetadata
     */
    private void setFieldsMetadata(List<Map> list, String key, FieldsMetadata fieldsMetadata) {
        list.forEach(item -> {
            item.forEach((k, v) -> {
                fieldsMetadata.addFieldAsList(key + StrUtil.DOT + k);
            });
        });
    }

    private void checkPrintDto(PrintDto dto) {
        Assert.isTrue(dto.getInPath() != null || dto.getIn() != null, "打印模板路径为空或路径不正确");
        Assert.isTrue(!ObjectUtil.isNull(dto.getJson()), "打印模板参数不能为空");
    }


}
